/** @file
 *
 * Testy, Virtual(-izable) Buffer of uint8_t*'s
 *
 * "Testy" -- the buffer gets mad when an attempt is made to access data
 *      beyond the bounds of the buffer. An exception is thrown.
 *
 * "Virtual" -- the buffer can have its own data, can use a subset of
 *      the data of a backing tvbuff, or can be a composite of
 *      other tvbuffs.
 *
 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef __TVBUFF_H__
#define __TVBUFF_H__

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
    Index is beyond the captured length of the tvbuff.
    This generally means that the capture was done with a "slice"
    length or "snapshot" length less than the maximum packet size,
    and a link-layer packet was cut short by that, so not all of the
    data in the link-layer packet was available.
**/
#define BoundsError        1

/**
    Index is beyond the contained length of the tvbuff.
    This generally means that the tvbuff was constructed as
    a subset of a parent tvbuff, based on a length specified
    by data in the packet, but the length in question runs
    past the reported length of the data in the parent tvbuff.
    That means that the packet is invalid, as the data indicating
    the length says the length exceeds what's contained in the
    packet.  It is therefore currently reported as a "Malformed
    packet".
**/
#define ContainedBoundsError    2

/**
    Index is beyond the reported length of the tvbuff.
    This generally means that the packet is invalid, i.e. whatever
    code constructed the packet and put it on the wire didn't put enough
    data into it.  It is therefore currently reported as a "Malformed
    packet".
**/
#define ReportedBoundsError    3

/**
    Index is beyond the contained length, and possibly the reported length,
    of the tvbuff, but we believe it is an unreassembled fragment, either
    because the "this is an unreassembled fragment" flag or pinfo->fragmented
    is set.  This means that the packet wasn't reassembled, but could possibly
    be correctly dissected if reassembly preferences were changed.  It is
    therefore not reported as a "Malformed packet".
**/
#define FragmentBoundsError    4

/**
    During dfilter parsing
**/
#define TypeError        5

/**
    A bug was detected in a dissector.

    DO NOT throw this with THROW(); that means that no details about
    the dissector error will be reported.  (Instead, the message will
    blame you for not providing details.)

    Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h.
**/
#define DissectorError        6

/**
    Index is out of range.
    An attempt was made to read past the end of a buffer.
    This error is specific to SCSI data transfers where for some CDBs
    it is normal that the data PDU might be short.
    I.e. ReportLuns initially called with allocation_length=8, just enough
    to get the "size" of lun list back after which the initiator will
    reissue the command with an allocation_length that is big enough.
**/
#define ScsiBoundsError        7

/**
    Running out of memory.
    A dissector tried to allocate memory but that failed.
**/
#define OutOfMemoryError    8

/**
    The reassembly state machine was passed a bad fragment offset,
    or other similar issues. We used to use DissectorError in these
    cases, but they're not necessarily the dissector's fault - if the packet
    contains a bad fragment offset, the dissector shouldn't have to figure
    that out by itself since that's what the reassembly machine is for.
**/
#define ReassemblyError         9


/**
 * "testy, virtual(-izable) buffer".  They are testy in that they get mad when
 * an attempt is made to access data beyond the bounds of their array. In that
 * case, they throw an exception.
 *
 * They are virtualizable in that new tvbuff's can be made from other tvbuffs,
 * while only the original tvbuff may have data. That is, the new tvbuff has
 * virtual data.
 */

struct tvbuff;
typedef struct tvbuff tvbuff_t;

/** @defgroup tvbuff Testy, Virtual(-izable) Buffers
 *
 * Dissector use and management
 *
 *  Consider a collection of tvbs as being a chain or stack of tvbs.
 *
 *  When dissecting a frame:
 *   The top-level dissector (packet.c) pushes the initial tvb (containing
 *   the complete frame) onto the stack (starts the chain) and then calls
 *   a sub-dissector which in turn calls the next sub-dissector and so on.
 *   Each sub-dissector may chain additional tvbs (see below) to the tvb
 *   handed to that dissector. After dissection is complete and control has
 *   returned to the top-level dissector, the chain of tvbs (stack) is free'd
 *   via a call to tvb_free_chain() (in epan_dissect_cleanup()).
 *
 * A dissector:
 *  - Can chain new tvbs (subset, real, composite) to the
 *    tvb handed to the dissector using tvb_new_subset_length_caplen(),
 *    tvb_new_subset_length(), tvb_new_subset_remaining(),
 *    tvb_new_child_real_data(), tvb_set_child_real_data_tvbuff(),
 *    tvb_composite_finalize(), and tvb_child_uncompress(). (Composite
 *    tvbs should reference only tvbs which are already part of the chain).
 *  - Must not save for later use (e.g., when dissecting another frame) a
 *    pointer to a tvb handed to the dissector; (A higher level function
 *    may very well free the chain thus leaving a dangling pointer).
 *    This (obviously) also applies to any tvbs chained to the tvb handed
 *    to the dissector.
 *  - Can create its own tvb chain (using tvb_new_real_data() which the
 *    dissector is free to manage as desired.
 * @{
 */

/** A "real" tvbuff contains a uint8_t* that points to real data.
 * The data is allocated and contiguous.
 *
 * A "subset" tvbuff has a backing tvbuff. It is a "window" through
 * which the program sees only a portion of the backing tvbuff.
 *
 * A "composite" tvbuff combines multiple tvbuffs sequentially to
 * produce a larger byte array.
 *
 * tvbuff's of any type can be used as the backing-tvbuff of a
 * "subset" tvbuff or as a member of a "composite" tvbuff.
 * "composite" tvbuffs can have member-tvbuffs of different types.
 *
 * Once a tvbuff is create/initialized/finalized, the tvbuff is read-only.
 * That is, it cannot point to any other data. A new tvbuff must be created if
 * you want a tvbuff that points to other data.
 *
 * tvbuff's are normally chained together to allow efficient de-allocation of
 * tvbuff's.
 */

typedef void (*tvbuff_free_cb_t)(void*);

/** Extracts 'number of bits' starting at 'bit offset'.
 * Returns a pointer to a newly initialized g_malloc'd REAL_DATA
 * tvbuff with the bits octet aligned.
 * Bits are counted from MSB (0) to LSB (7) within octets.
 */
//tvbuff_t *tvb_new_octet_aligned(tvbuff_t *tvb,
//    uint32_t bit_offset, int32_t no_of_bits);

/** Extracts 'number of bits' starting at 'bit offset'.
 * Bits are counted from LSB (0) to MSB (7) within octets.
 */
tvbuff_t *tvb_new_octet_right_aligned(tvbuff_t *tvb,
    uint32_t bit_offset, int32_t no_of_bits);

tvbuff_t *tvb_new_chain(tvbuff_t *parent, tvbuff_t *backing);

tvbuff_t *tvb_clone(tvbuff_t *tvb);

tvbuff_t *tvb_clone_offset_len(tvbuff_t *tvb, unsigned offset, unsigned len);

/** Free a tvbuff_t and all tvbuffs chained from it
 * The tvbuff must be 'the 'head' (initial) tvb of a chain or
 * must not be in a chain.
 * If specified, a callback to free the tvbuff data will be invoked
 * for each tvbuff free'd */
void tvb_free(tvbuff_t *tvb);

/** Free the tvbuff_t and all tvbuffs chained from it.
 * The tvbuff must be 'the 'head' (initial) tvb of a chain or
 * must not be in a chain.
 * If specified, a callback to free the tvbuff data will be invoked
 * for each tvbuff free'd */
void tvb_free_chain(tvbuff_t *tvb);

/** Set a callback function to call when a tvbuff is actually freed
 * One argument is passed to that callback --- a void* that points
 * to the real data. Obviously, this only applies to a
 * "real" tvbuff. */
void tvb_set_free_cb(tvbuff_t *tvb, const tvbuff_free_cb_t func);

/** Attach a "real" tvbuff to a parent tvbuff. This connection is used
 * during a tvb_free_chain()... the "child" "real" tvbuff acts as if it
 * is part of the chain-of-creation of the parent tvbuff, although it
 * isn't. This is useful if you need to take the data from some tvbuff,
 * run some operation on it, like decryption or decompression, and make
 * a new tvbuff from it, yet want the new tvbuff to be part of the chain.
 * The reality is that the new tvbuff *is* part of the "chain of creation",
 * but in a way that these tvbuff routines are ignorant of. Use this
 * function to make the tvbuff routines knowledgable of this fact. */
//void tvb_set_child_real_data_tvbuff(tvbuff_t *parent,
//    tvbuff_t *child);

tvbuff_t *tvb_new_child_real_data(tvbuff_t *parent,
    const uint8_t *data, const unsigned length, const int reported_length);

/** Create a tvbuff backed by existing data. Can throw ReportedBoundsError.
 * Normally, a callback to free the data should be registered using
 * tvb_set_free_cb(); when this tvbuff is freed, then your callback will be
 * called, and at that time you can free your original data. */
tvbuff_t *tvb_new_real_data(const uint8_t *data,
    const unsigned length, const int reported_length);

/** Create a tvbuff that's a subset of another tvbuff, with the captured
 * length explicitly given. You probably want tvb_new_subset_length() or
 * tvb_new_subset_remaining() instead.
 *
 * @param backing The backing tvbuff onto which the new tvbuff is a view
 * @param backing_offset If positive, is the offset from the beginning of
 * the backing tvbuff at which the new tvbuff's data begins, and, if
 * negative, is the offset from the end of the backing tvbuff at which
 * the new tvbuff's data begins.
 * @param backing_length The length of the data to include in the new
 * tvbuff, starting with the byte at 'backing_offset'; if -1, it
 * means "to the end of the backing tvbuff".  It can be 0, although
 * the usefulness of the buffer would be rather limited.  The length
 * actually included will be no more than the reported length.
 * @param reported_length The reported length of the new tvbuff; if -1, it
 * means "the reported length to the end of the backing tvbuff".  It can
 * be 0, although the usefulness of the buffer would be rather limited.
 *
 * @return A tvbuff that is a subset of the backing tvbuff beginning at
 * backing_offset (which is offset 0 in the subset) and with the given
 * reported_length, with captured length no more than backing_length.
 *
 * @note In most cases use tvb_new_subset_length() (or equivalently, pass -1
 * as 'backing_length') or tvb_new_subset_remaining() instead.  Use this when
 * the backing tvbuff includes bytes at the end that must not be included in
 * the subset regardless of the reported length, such as an FCS or padding.
 * In such cases it may still be simpler to call tvb_new_subset_length()
 * twice, once to remove the trailing bytes and once to select the chosen
 * payload bytes.
 *
 * @warning Will throw BoundsError if 'backing_offset'/'length'
 * is beyond the bounds of the backing tvbuff.
 * Can throw ReportedBoundsError. */
tvbuff_t *tvb_new_subset_length_caplen(tvbuff_t *backing,
    const int backing_offset, const int backing_length,
    const int reported_length);

/**
 * Similar to tvb_new_subset_length_caplen() but with captured length calculated
 * to fit within the existing captured length and the specified
 * reported length.
 * Can throw ReportedBoundsError. */
tvbuff_t *tvb_new_subset_length(tvbuff_t *backing,
    const int backing_offset, const int reported_length);

/** Similar to tvb_new_subset_length_caplen() but with backing_length and reported_length set
 * to -1.  Can throw ReportedBoundsError. */
tvbuff_t *tvb_new_subset_remaining(tvbuff_t *backing,
    const int backing_offset);

/*
* Both tvb_composite_append and tvb_composite_prepend can throw
 * BoundsError if member_offset/member_length goes beyond bounds of
 * the 'member' tvbuff. */

/** Append to the list of tvbuffs that make up this composite tvbuff */
void tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member);

/** Prepend to the list of tvbuffs that make up this composite tvbuff */
extern void tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member);

/** Create an empty composite tvbuff. */
tvbuff_t *tvb_new_composite(void);

/** Mark a composite tvbuff as initialized. No further appends or prepends
 * occur, data access can finally happen after this finalization. */
void tvb_composite_finalize(tvbuff_t *tvb);


/* Get amount of captured data in the buffer (which is *NOT* necessarily the
 * length of the packet). You probably want tvb_reported_length instead. */
unsigned tvb_captured_length(const tvbuff_t *tvb);

/** Computes bytes to end of buffer, from offset (which can be negative,
 * to indicate bytes from end of buffer). Function returns 0 if offset is
 * either at the end of the buffer or out of bounds. No exception is thrown.
 * You probably want tvb_reported_length_remaining instead. */
int tvb_captured_length_remaining(const tvbuff_t *tvb, const int offset);

/** Same as above, but throws an exception if the offset is out of bounds. */
unsigned tvb_ensure_captured_length_remaining(const tvbuff_t *tvb,
    const int offset);

/* Checks (w/o throwing exception) that the bytes referred to by
 * 'offset'/'length' actually exist in the buffer */
bool tvb_bytes_exist(const tvbuff_t *tvb, const int offset,
    const int length);

/** Checks that the bytes referred to by 'offset'/'length', where 'length'
 * is a 64-bit unsigned integer, actually exist in the buffer, and throws
 * an exception if they aren't. */
void tvb_ensure_bytes_exist64(const tvbuff_t *tvb,
    const int offset, const uint64_t length);

/** Checks that the bytes referred to by 'offset'/'length' actually exist
 * in the buffer, and throws an exception if they aren't. */
void tvb_ensure_bytes_exist(const tvbuff_t *tvb,
    const int offset, const int length);

/* Checks (w/o throwing exception) that offset exists in buffer */
bool tvb_offset_exists(const tvbuff_t *tvb,
    const int offset);

/* Get reported length of buffer */
unsigned tvb_reported_length(const tvbuff_t *tvb);

/** Computes bytes of reported packet data to end of buffer, from offset
 * (which can be negative, to indicate bytes from end of buffer). Function
 * returns 0 if offset is either at the end of the buffer or out of bounds.
 * No exception is thrown. */
int tvb_reported_length_remaining(const tvbuff_t *tvb,
    const int offset);

/** Same as above, but throws an exception if the offset is out of bounds. */
unsigned tvb_ensure_reported_length_remaining(const tvbuff_t *tvb,
    const int offset);

/** Set the reported length of a tvbuff to a given value; used for protocols
   whose headers contain an explicit length and where the calling
   dissector's payload may include padding as well as the packet for
   this protocol.

   Also adjusts the available and contained length. */
void tvb_set_reported_length(tvbuff_t *tvb, const unsigned);

/* Repair a tvbuff where the captured length is greater than the
 * reported length; such a tvbuff makes no sense, as it's impossible
 * to capture more data than is in the packet.
 */
void tvb_fix_reported_length(tvbuff_t *tvb);

unsigned tvb_offset_from_real_beginning(const tvbuff_t *tvb);

/* Returns the offset from the first byte of real data. */
int tvb_raw_offset(tvbuff_t *tvb);

/** Set the "this is a fragment" flag. This affects whether
 * FragmentBoundsError is thrown instead of ContainedBoundsError
 * or ReportedBoundsError. */
void tvb_set_fragment(tvbuff_t *tvb);

struct tvbuff *tvb_get_ds_tvb(tvbuff_t *tvb);


/************** START OF ACCESSORS ****************/
/* All accessors will throw an exception if appropriate */

uint8_t tvb_get_uint8(tvbuff_t *tvb, const int offset);
int8_t tvb_get_int8(tvbuff_t *tvb, const int offset);

uint16_t tvb_get_ntohs(tvbuff_t *tvb, const int offset);
int16_t tvb_get_ntohis(tvbuff_t *tvb, const int offset);
uint32_t tvb_get_ntoh24(tvbuff_t *tvb, const int offset);
int32_t tvb_get_ntohi24(tvbuff_t *tvb, const int offset);
uint32_t tvb_get_ntohl(tvbuff_t *tvb, const int offset);
int32_t tvb_get_ntohil(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_ntoh40(tvbuff_t *tvb, const int offset);
int64_t tvb_get_ntohi40(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_ntoh48(tvbuff_t *tvb, const int offset);
int64_t tvb_get_ntohi48(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_ntoh56(tvbuff_t *tvb, const int offset);
int64_t tvb_get_ntohi56(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_ntoh64(tvbuff_t *tvb, const int offset);
int64_t tvb_get_ntohi64(tvbuff_t *tvb, const int offset);
float tvb_get_ntohieee_float(tvbuff_t *tvb, const int offset);
double tvb_get_ntohieee_double(tvbuff_t *tvb, const int offset);

uint16_t tvb_get_letohs(tvbuff_t *tvb, const int offset);
int16_t tvb_get_letohis(tvbuff_t *tvb, const int offset);
uint32_t tvb_get_letoh24(tvbuff_t *tvb, const int offset);
int32_t tvb_get_letohi24(tvbuff_t *tvb, const int offset);
uint32_t tvb_get_letohl(tvbuff_t *tvb, const int offset);
int32_t tvb_get_letohil(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_letoh40(tvbuff_t *tvb, const int offset);
int64_t tvb_get_letohi40(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_letoh48(tvbuff_t *tvb, const int offset);
int64_t tvb_get_letohi48(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_letoh56(tvbuff_t *tvb, const int offset);
int64_t tvb_get_letohi56(tvbuff_t *tvb, const int offset);
uint64_t tvb_get_letoh64(tvbuff_t *tvb, const int offset);
int64_t tvb_get_letohi64(tvbuff_t *tvb, const int offset);
float tvb_get_letohieee_float(tvbuff_t *tvb, const int offset);
double tvb_get_letohieee_double(tvbuff_t *tvb, const int offset);

uint16_t tvb_get_uint16(tvbuff_t *tvb, const int offset, const unsigned encoding);
int16_t tvb_get_int16(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint32_t tvb_get_uint24(tvbuff_t *tvb, const int offset, const unsigned encoding);
int32_t tvb_get_int24(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint32_t tvb_get_uint32(tvbuff_t *tvb, const int offset, const unsigned encoding);
int32_t tvb_get_int32(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint64_t tvb_get_uint40(tvbuff_t *tvb, const int offset, const unsigned encoding);
int64_t tvb_get_int40(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint64_t tvb_get_uint48(tvbuff_t *tvb, const int offset, const unsigned encoding);
int64_t tvb_get_int48(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint64_t tvb_get_uint56(tvbuff_t *tvb, const int offset, const unsigned encoding);
int64_t tvb_get_int56(tvbuff_t *tvb, const int offset, const unsigned encoding);
uint64_t tvb_get_uint64(tvbuff_t *tvb, const int offset, const unsigned encoding);
int64_t tvb_get_int64(tvbuff_t *tvb, const int offset, const unsigned encoding);
float tvb_get_ieee_float(tvbuff_t *tvb, const int offset, const unsigned encoding);
double tvb_get_ieee_double(tvbuff_t *tvb, const int offset, const unsigned encoding);

/* Similar to above, but returns a GByteArray based on the case-insensitive
 * hex-char strings with optional separators, and with optional leading spaces.
 * The separators allowed are based on the ENC_SEP_* passed in the encoding param.
 *
 * The passed-in bytes is set to the values, and its pointer is also the return
 * value or NULL on error. The GByteArray bytes must be pre-constructed with
 * g_byte_array_new().
 */
GByteArray* tvb_get_string_bytes(tvbuff_t *tvb, const int offset, const int length,
                                 const unsigned encoding, GByteArray* bytes, int *endoff);

/*
 * Fetch 16-bit and 32-bit values in host byte order.
 * Used for some pseudo-headers in pcap/pcapng files, in which the
 * headers are, when capturing, in the byte order of the host, and
 * are converted to the byte order of the host reading the file
 * when reading a capture file.
 */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define tvb_get_h_uint16  tvb_get_letohs
#define tvb_get_h_uint32  tvb_get_letohl
#elif G_BYTE_ORDER == G_BIG_ENDIAN
#define tvb_get_h_uint16  tvb_get_ntohs
#define tvb_get_h_uint32  tvb_get_ntohl
#else
#error "Unsupported byte order"
#endif

/* Fetch a specified number of bits from bit offset in a tvb.  All of these
 * functions are equivalent, except for the type of the return value.  Note
 * that the parameter encoding (where supplied) is meaningless and ignored */

/* get 1 - 8 bits returned in a uint8_t */
uint8_t tvb_get_bits8(tvbuff_t *tvb, unsigned bit_offset,
    const int no_of_bits);

/* get 1 - 16 bits returned in a uint16_t */
uint16_t tvb_get_bits16(tvbuff_t *tvb, unsigned bit_offset,
    const int no_of_bits, const unsigned encoding);

/* get 1 - 32 bits returned in a uint32_t */
uint32_t tvb_get_bits32(tvbuff_t *tvb, unsigned bit_offset,
    const int no_of_bits, const unsigned encoding);

/* get 1 - 64 bits returned in a uint64_t */
uint64_t tvb_get_bits64(tvbuff_t *tvb, unsigned bit_offset,
    const int no_of_bits, const unsigned encoding);

/**
 *  This function has EXACTLY the same behavior as
 *  tvb_get_bits32()
 */
uint32_t tvb_get_bits(tvbuff_t *tvb, const unsigned bit_offset,
    const int no_of_bits, const unsigned encoding);


void *tvb_memcpy(tvbuff_t *tvb, void *target, const int offset, size_t length);
void *tvb_memdup(tvbuff_t *tvb, const int offset, size_t length);
const uint8_t *tvb_get_ptr(tvbuff_t *tvb, const int offset, const int length);


/** Find first occurrence of needle in tvbuff, starting at offset. Searches
 * at most maxlength number of bytes; if maxlength is -1, searches to
 * end of tvbuff.
 * Returns the offset of the found needle, or -1 if not found.
 * Will not throw an exception, even if maxlength exceeds boundary of tvbuff;
 * in that case, -1 will be returned if the boundary is reached before
 * finding needle. */
int tvb_find_uint8(tvbuff_t *tvb, const int offset,
    const int maxlength, const uint8_t needle);

//static inline int tvb_find_guint8(tvbuff_t* tvb, const int offset,
//    const int maxlength, const uint8_t needle) {
//    return tvb_find_uint8(tvb, offset, maxlength, needle);
//}

/** Same as tvb_find_uint8() with 16bit needle. */
int tvb_find_uint16(tvbuff_t *tvb, const int offset,
    const int maxlength, const uint16_t needle);

static inline int tvb_find_guint16(tvbuff_t* tvb, const int offset,
    const int maxlength, const uint16_t needle) {
    return tvb_find_uint16(tvb, offset, maxlength, needle);
}

/** Find size of stringz (NUL-terminated string) by looking for terminating
 * NUL.  The size of the string includes the terminating NUL.
 *
 * If the NUL isn't found, it throws the appropriate exception.
 */
unsigned tvb_strsize(tvbuff_t *tvb, const int offset);

/** Find size of UCS-2 or UTF-16 stringz (NUL-terminated string) by
 * looking for terminating 16-bit NUL.  The size of the string includes
 * the terminating NUL.
 *
 * If the NUL isn't found, it throws the appropriate exception.
 */
unsigned tvb_unicode_strsize(tvbuff_t *tvb, const int offset);

/** Find length of string by looking for end of zero terminated string, up to
 * 'maxlength' characters'; if 'maxlength' is -1, searches to end
 * of tvbuff.
 * Returns -1 if 'maxlength' reached before finding EOS. */
int tvb_strnlen(tvbuff_t *tvb, const int offset, const unsigned maxlength);

/**
 * Format the data in the tvb from offset for size.
 */
char *tvb_format_text(tvbuff_t *tvb, const int offset, const int size);

/**
 * Given an allocator scope, a tvbuff, a byte offset, a byte length, and
 * a string encoding, with the specified offset and length referring to
 * a string in the specified encoding:
 *
 *    allocate a buffer using the specified scope;
 *
 *    convert the string from the specified encoding to UTF-8, possibly
 *    mapping some characters or invalid octet sequences to the Unicode
 *    REPLACEMENT CHARACTER, and put the resulting UTF-8 string, plus a
 *    trailing '\0', into that buffer;
 *
 *    and return a pointer to the buffer.
 *
 * Throws an exception if the tvbuff ends before the string does.
 *
 * If scope is set to NULL it is the user's responsibility to wmem_free()
 * the memory allocated. Otherwise memory is automatically freed when the
 * scope lifetime is reached.
 */
uint8_t *tvb_get_string_enc(tvbuff_t *tvb, const int offset,
                            const int length, const unsigned encoding);

uint8_t *tvb_get_stringzpad(tvbuff_t *tvb, const int offset,
                            const int length, const unsigned encoding);

uint8_t *tvb_get_stringz_enc(tvbuff_t *tvb, const int offset,
                             int *lengthp, const unsigned encoding);

char *tvb_bytes_to_str(tvbuff_t *tvb, const int offset, const int len);

int tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, const int haystack_offset);

/**
 * Extract a variable length integer from a tvbuff.
 * Each byte in a varint, except the last byte, has the most significant bit (msb)
 * set -- this indicates that there are further bytes to come. For example,
 *   1010 1100 0000 0010 is 300
 *
 * @param tvb The tvbuff in which we are extracting integer.
 * @param offset The offset in tvb from which we begin trying to extract integer.
 * @param maxlen The maximum distance from offset that we may try to extract integer
 * @param value  if parsing succeeds, parsed varint will store here.
 * @param encoding The ENC_* that defines the format (e.g., ENC_VARINT_PROTOBUF, ENC_VARINT_QUIC, ENC_VARINT_ZIGZAG, ENC_VARINT_SDNV)
 * @return   the length of this varint in tvb. 0 means parsing failed.
 */
unsigned tvb_get_varint(tvbuff_t *tvb, unsigned offset, unsigned maxlen, uint64_t *value, const unsigned encoding);

/************** END OF ACCESSORS ****************/

/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __TVBUFF_H__ */

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 4
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=8 expandtab:
 * :indentSize=4:tabSize=8:noTabs=true:
 */
